package com.qf.base.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * description:雪花算法工具类
 * 第一部分   是1bit 就是一个0，没有任何意义 是个long值 不希望是一个负值
 * 第二部分   4 bit 时间戳
 * 第三部分   5 bit 机房id
 * 第四部分   5 bit 机器id
 * 第五部分   12bit 序列号
 */
@Component
public class SnowFlakeUtil {
    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());

        System.out.println((1 << 5) - 1);
        System.out.println(-1 ^ (-1 << 5));

        System.out.println(new SnowFlakeUtil().nextId());
    }

    /**
     * 学法算法的时间的起点
     * 一你问时间戳只有41位，虽有每次算法将在此时课开始往后的69年中，都可以使用
     */
    private long twepoch = 1632793014945L;
    /**
     * 机器id
     */
    @Value("${snowflake.worker:0}")
    private long workerId;
    /**
     * 机房id
     */

    @Value("${snowflake.dataCenterId:0}")
    private long dataCenterId;
    /**
     * 序号
     */
    private long sequence;

    /**
     * 机房id的位数
     */
    private long dataCenterIdBits = 5L;
    /**
     * 机器id的位数
     */
    private long workerIdBits = 5L;
    /**
     * 机房id的最大值
     */
    private long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);


    /**
     * 机器id的最大值
     */
    private long maxWorkerId = -1L ^ (-1L << workerIdBits);


    /**
     * 序列号位数
     */
    private long sequenceBits = 12L;
    /**
     * 序列号的最大值
     */
    private long maxSequence = -1L ^ (-1L << sequenceBits);
    /**
     * 时间戳左移位数
     */

    private long timestampShift = sequenceBits + dataCenterIdBits + workerIdBits;

    /**
     * 机房id左移位数
     */

    private long dataCenterIdShift = sequenceBits + workerIdBits;
    /**
     * 机器id左移位数
     */
    private long workerIdShift = sequenceBits;

    /**
     * 总体记录时间的变量
     */

    private long lastTimestamp = -1L;

    /**
     * 封装获取时间的方法
     */
    public long time() {
        return System.currentTimeMillis();
    }

    /**
     * 获取一个新的时间
     */
    private long nextTime(long lastTimestamp) {
        long timestamp = time();
        while (timestamp <= lastTimestamp) {
            timestamp = time();
        }
        return timestamp;
    }

    /**
     * 生成与拼装算法
     * 总体上是一个 long 值
     * <p>
     * -------------------------------------------
     * |0|        41位       | 5位 | 5位 |   12位  |
     * --------------------------------------------
     * <p>
     * （时间戳左移22位）+
     * （机房id左移17位）+
     * （机器id左移12位）+
     * （序列号）
     */

    public synchronized long nextId() {
        //获取当前时间
        long timestamp = time();

        // 和上一次作比较
        if (timestamp < lastTimestamp) {
            return -1;
        }

        //1毫秒内的并发
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & maxSequence;
            if (sequence == 0) {
                //加到最大值
                //获取一个新的时间
                timestamp = nextTime(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        //记录这一次的生成雪花算法的时间
        lastTimestamp = timestamp;
        return ((timestamp - twepoch) << timestampShift) |
                (dataCenterId << dataCenterIdBits) |
                (workerId << workerIdShift) |
                (sequence);
    }


}
